//#include "StdAfx.h"
#include "vector3.h"
#include "Misc.h"
#include <cassert>

	
namespace RayTrace{

vector3 vector3::ZeroUnit=vector3(0.0f,0.0f,0.0f);

vector3::vector3(void)
{
}

vector3::~vector3(void)
{
}

vector3::vector3(float _x,float _y,float _z):x(_x),y(_y),z(_z)
{

}
vector3 vector3::operator /(const float &b) const
{
	vector3 ans;
	ans.x=this->x/b;
	ans.y=this->y/b;
	ans.z=this->z/b;
	return ans;
}
vector3 vector3::operator *(const float b) const
{
	vector3 ans;
	ans.x=this->x*b;
	ans.y=this->y*b;
	ans.z=this->z*b;
	return ans;
}
vector3& vector3::operator +=(const vector3 &b)
{
	x+=b.x;
	y+=b.y;
	z+=b.z;
	return (*this);
}
vector3 vector3::operator +(const vector3 &b) const
{
	vector3 ans=(*this);
	ans+=b;
	//ans.x=this->x+b.x;
	//ans.y=this->y+b.y;
	//ans.z=this->z+b.z;
	return ans;
}
vector3 vector3::operator -(const vector3 &b) const
{
	vector3 ans;
	ans.x=this->x-b.x;
	ans.y=this->y-b.y;
	ans.z=this->z-b.z;
	return ans;
}
vector3 vector3::Normalize() const
{
	vector3 ans;
	vector3 b=*this;
	float d=1.0f;
	if (fabs(d) > MMIN)//?
		d=sqrt(b.x*b.x+b.y*b.y+b.z*b.z);
	else{
		d = 1.0f;
	}
	ans.x=b.x/d;
	ans.y=b.y/d;
	ans.z=b.z/d;
	return ans;
}
float  vector3::Dot(const vector3 &a,const vector3 &b)
{
	return a.x*b.x+a.y*b.y+a.z*b.z;
}

double vector3::Distant(const vector3 &a,const vector3 &b)
{
	return sqrt(powf((a.x-b.x),2)+powf((a.y-b.y),2)+powf((a.z-b.z),2));

}
vector3 vector3::LimitInColorRange(const vector3 &a)
{
	vector3 ans=a;
	if (ans.x>1.0f) ans.x=1.0f;
	if (ans.y>1.0f) ans.y=1.0f;
	if (ans.z>1.0f) ans.z=1.0f;
	return ans;
}
vector3 vector3::Reflect( vector3 in, vector3 normal)
{
	//vector3 L=(in).Normalize();
	//vector3 N=normal.Normalize();
	//vector3 R=(L-N*2.0f*vector3::Dot(L,N)).Normalize();
	//return R;
	return vector3( in - ( 2 * Dot(in,normal)* normal ) ).Normalize();
}
vector3 vector3::Refract( vector3 in, vector3 normal,float n)
{
	vector3 N=normal.Normalize();
	double cosine=Dot(N,in);
	double sinT2=n*n*(1.0-cosine*cosine);
	if (sinT2>1.0f)
	{
		return vector3(0.0f,0.0f,0.0f);
	}
	return in*n-N*float(n+sqrt(1.0-sinT2));
}
vector3 vector3::Cross(const vector3 &a,const vector3 &b)
{
	return vector3(
			a.y * b.z - a.z * b.y,
			a.z * b.x - a.x * b.z,
			a.x * b.y - a.y * b.x);

}
vector3 operator *(float a,const vector3& b)
{
	return vector3(b.x*a,b.y*a,b.z*a);
}

float  vector3::Length() const
{
	return sqrt(x*x+y*y+z*z);
}
float& vector3::operator [] (int n)
{
	switch(n)
	{
	case 0:
		return x;
		break;
	case 1:
		return y;
		break;
	case 2:
		return z;
	    break;
	default:
		//this will never happen
		assert(1);
		return x;
	    break;
	}
}

float vector3::operator[] (int n ) const
{
	switch(n)
	{
	case 0:
		return x;
		break;
	case 1:
		return y;
		break;
	case 2:
		return z;
		break;
	default:
		//this will never happen
		assert(1);
		return x;
		break;
	}
}
}
